#include <string>
#include "ohos_egl_render.h"
#include "rtc_base/logging.h"
#include "common_video/util/gl_util.h"
#include "common_video/ohos/ohos_egl_context_manager.h"

namespace webrtc {
namespace {
constexpr const char* EGL_RENDER_TAG = "EGLRender";
} // namespace

bool EGLRender::InitContext(void *window, void* share_context, int width, int height) {
  RTC_LOG(LS_INFO) << EGL_RENDER_TAG << " InitContext execute. width: " << width << ", height: " << height;
  if ((window == nullptr) || (width <= 0) || (height <= 0)) {
    RTC_LOG(LS_ERROR) << EGL_RENDER_TAG << " InitContext: param error";
    return false;
  }

  UpdateSize(width, height);
  auto eglWindow = reinterpret_cast<EGLNativeWindowType>(window);
  if (!eglWindow) {
    RTC_LOG(LS_ERROR) << EGL_RENDER_TAG << " InitContext. eglWindow_ is null";
    return false;
  }

  // Create context.
  EGLContext shareContext = EGL_NO_CONTEXT;
  if (share_context) {
    shareContext = reinterpret_cast<EGLContext>(share_context);
  } else {
    auto eglContextResource = OhosEGLContextManager::GetInstance().GetEGLContextResource(); 
    if (eglContextResource->eglContext_ && eglContextResource->eglContext_->IsEglContextReady()) {
      shareContext = eglContextResource->eglContext_->GetEGLContext();
      RTC_LOG(LS_INFO) << EGL_RENDER_TAG << " InitContext. with share context";
    }
  }
  
  // Create Surface
  eglRenderContext_ = std::make_shared<EGLRenderContext>();
  eglRenderContext_->Init(shareContext);
  eglSurface_ = eglRenderContext_->CreateEglSurface(eglWindow, NULL);

  // Reset buffer bit
  ClearColor(background_color_);

  // Necessary for YUV frames with odd width.
  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  return true;
}

void EGLRender::SetBackgroundColor(const GLfloat color[]) {
  RTC_LOG(LS_INFO) << EGL_RENDER_TAG << " SetBackgroundColor";
  std::copy(color, color + 4, background_color_);
}

void EGLRender::ClearColor(const GLfloat color[]) {
  RTC_LOG(LS_INFO) << EGL_RENDER_TAG << " ClearColor";
  PrepareDraw();
  ClearBufferColor(color);

  if (!FinishDraw()) {
    RTC_LOG(LS_ERROR) << EGL_RENDER_TAG << " ClearColor. finish failed";
  }
}

void EGLRender::DrawFrame(OhosVideoBuffer::TextureBuffer buffer, float *matrix, int frameWidth, int frameHeight, int viewportX, int viewportY, int viewportWidth, int viewportHeight) {
  PrepareDraw();
  ClearBufferColor(background_color_);
  glDrawer_->DrawFrame(buffer, matrix, frameWidth, frameHeight, viewportX, viewportY, viewportWidth, viewportHeight);
  if (!FinishDraw()) {
    RTC_LOG(LS_ERROR) << EGL_RENDER_TAG << " DrawOes. finish failed";
  }
}

void EGLRender::UpdateSize(int width, int height) {
  width_ = width;
  height_ = height;
  RTC_LOG(LS_INFO) << EGL_RENDER_TAG << " UpdateSize. width: " << width_ << " height: " << height_;
}

bool EGLRender::HasSurface() {
  return eglSurface_ != nullptr;
}

void EGLRender::Release() {
	if (eglRenderContext_) {
		if (eglSurface_ != EGL_NO_SURFACE) {
      eglRenderContext_->DestroyEglSurface(eglSurface_);
    }
    eglSurface_ = EGL_NO_SURFACE;  
    eglRenderContext_.reset();
	}

  if (glDrawer_) {
    glDrawer_->CleanGLResources();
  }
}

void EGLRender::ClearBufferColor(const GLfloat color[]) {
  glClearColor(color[0], color[1], color[2], color[3]);
  glClear(GL_COLOR_BUFFER_BIT);
}

GLboolean EGLRender::PrepareDraw() {
	if (eglRenderContext_ == nullptr || !eglRenderContext_->IsEglContextReady()) {
    RTC_LOG(LS_ERROR) << EGL_RENDER_TAG << " PrepareDraw. context error";
    return GL_FALSE;
  }
  if (eglSurface_ == EGL_NO_SURFACE) {
    RTC_LOG(LS_ERROR) << EGL_RENDER_TAG << " PrepareDraw. surface error";
    return GL_FALSE;
  }
  eglRenderContext_->MakeCurrent(eglSurface_);
	
  if (!glDrawer_) {
    glDrawer_ = std::make_shared<OhosGLDrawer>();
    glDrawer_->CreateGLResources();
  }

  return GL_TRUE;
}

bool EGLRender::FinishDraw() {
	eglRenderContext_->SwapBuffers(eglSurface_);
  return true;
}
}
